/*
 * AnimSwitch.java
 * classes : cc.core.animswitch.AnimSwitch
 * @author YuanChao
 * V 1.0.0
 * Create at 2015年8月21日 上午12:01:46
 */
package cc.core.animswitch;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Build;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;

import com.nineoldandroids.animation.Animator;
import com.nineoldandroids.animation.Animator.AnimatorListener;
import com.nineoldandroids.animation.ValueAnimator;
import com.nineoldandroids.animation.ValueAnimator.AnimatorUpdateListener;

/**
 * cc.core.animswitch.AnimSwitch
 * @author YuanChao <br/>
 * create at 2015年8月22日 上午12:01:46
 */
public class AnimSwitch extends View {

	private Paint bgPaint = new Paint();
	private Paint circlePaint = new Paint();
	private ValueAnimator transAnim;
	private RectF circleRect;
	private OnSwitchChangedListener switchListener;

	private float posX;
	private float switchHeight = 100f;
	private float switchPadding;
	// private float defColor = 0xffa8a6a6;
	// private float colorOffset = Math.abs(defColor - 0xff00a0ea);
	private int[] onRgb = new int[] { 0, 160, 234 };
	private int[] offRgb = new int[] { 168, 166, 166 };
	private int[] defRgbOffset;
	private boolean isOn;
	private boolean isAnimEnd = true;

	public AnimSwitch(Context context, AttributeSet attrs) {
		super(context, attrs);
		init(context, attrs);
	}

	public AnimSwitch(Context context) {
		super(context);
		init(context, null);
	}

	@SuppressLint("NewApi")
	private void init(Context context, AttributeSet attrs) {
		if (Build.VERSION.SDK_INT > 11)
			setLayerType(View.LAYER_TYPE_SOFTWARE, null);
		caculateRgb();
		bgPaint.setStyle(Paint.Style.FILL);// 充满
		bgPaint.setColor(Color.LTGRAY);
		bgPaint.setAntiAlias(true);// 抗锯齿

		circlePaint.setAntiAlias(true);
		circlePaint.setColor(Color.WHITE);
		circleRect = new RectF(0, 0, switchHeight * 2, switchHeight);
		addListener();
	}

	private void addListener() {
		getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {

			@Override
			public void onGlobalLayout() {
				getViewTreeObserver().removeGlobalOnLayoutListener(this);
				if (isOn)
					setOn(false);
				else
					setOff(false);
			}
		});
		setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				setSwitch();
			}
		});
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		// 绘制背景圆角矩形
		circleRect.set(0, 0, switchHeight * 2, switchHeight);
		canvas.drawRoundRect(circleRect, switchHeight, switchHeight, bgPaint);// 第二个参数是x半径，第三个参数是y半径
		canvas.drawCircle(switchHeight / 2 + posX, switchHeight / 2, switchHeight / 2 - switchPadding, circlePaint);
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

		// 获取宽度的模式
		int widthMode = MeasureSpec.getMode(widthMeasureSpec);

		// 获得宽度
		int width = View.MeasureSpec.getSize(widthMeasureSpec);

		// 计算测量模式
		switch (widthMode) {
		case MeasureSpec.UNSPECIFIED:
		case MeasureSpec.AT_MOST:
			switchHeight = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 25, getResources().getDisplayMetrics());
			break;
		case MeasureSpec.EXACTLY:
			switchHeight = width / 2;
			break;
		}

		// 圆形的边距设置成高度的1/10
		switchPadding = switchHeight * 0.15f;

		// 设置测量尺寸值
		setMeasuredDimension((int) (switchHeight * 2), (int) switchHeight); // 这里面是原始的大小，需要重新计算可以修改本行
	}

	public void startAnim() {

		float value = isOn ? switchHeight : -switchHeight;
		if (isOn) {
			transAnim = ValueAnimator.ofFloat(value);
		} else {
			transAnim = ValueAnimator.ofFloat(switchHeight, 0);
		}
		transAnim.setDuration(300);
		transAnim.addUpdateListener(new AnimatorUpdateListener() {

			@Override
			public void onAnimationUpdate(ValueAnimator animation) {
				posX = (Float) animation.getAnimatedValue();
				float progress = posX / switchHeight;
				bgPaint.setColor(Color.rgb((int) (onRgb[0] + defRgbOffset[0] * (1 - progress)), (int) (onRgb[1] + defRgbOffset[1] * (1 - progress)),
						(int) (onRgb[2] + defRgbOffset[2] * (1 - progress))));
				invalidate();
			}
		});
		transAnim.addListener(new AnimatorListener() {

			@Override
			public void onAnimationStart(Animator animation) {
				isAnimEnd = false;
			}

			@Override
			public void onAnimationRepeat(Animator animation) {
			}

			@Override
			public void onAnimationEnd(Animator animation) {
				isAnimEnd = true;
			}

			@Override
			public void onAnimationCancel(Animator animation) {
			}
		});
		transAnim.start();
	}

	public void setSwitch() {
		if (!isAnimEnd)
			return;
		isOn = !isOn;
		if (isOn)
			setOn();
		else
			setOff();
		if (switchListener != null)
			switchListener.onChanged(isOn);
	}

	public boolean isOn() {
		return isOn;
	}

	public void setOn() {
		isOn = true;
		startAnim();
	}

	public void setOff() {
		isOn = false;
		startAnim();
	}

	/**
	 * <p> 如果你是在进入界面的初始化方法中设置switch的开关状态，请调用此方法，不要调用 {@code #setOn()}方法，因为此方法会有动画有延时。</p>
	 * @param smoothly
	 */
	public void setOn(boolean smoothly) {
		isOn = true;
		if (!smoothly) {
			posX = switchHeight;
			bgPaint.setColor(Color.rgb(onRgb[0], onRgb[1], onRgb[2]));
			circlePaint.setColor(Color.WHITE);
			invalidate();
		} else
			startAnim();
	}

	public void setOff(boolean smoothly) {
		isOn = false;
		if (!smoothly) {
			posX = 0;
			bgPaint.setColor(Color.rgb(offRgb[0], offRgb[1], offRgb[2]));
			circlePaint.setColor(Color.WHITE);
			invalidate();
		} else
			startAnim();
	}

	/**
	 * 监听回调
	 * cc.core.animswitch.OnSwitchChangedListener
	 * @author YuanChao <br/>
	 * create at 2015年8月22日 上午1:18:26
	 */
	public interface OnSwitchChangedListener {
		public void onChanged(boolean isOn);
	}

	public void setSwitchListener(OnSwitchChangedListener switchListener) {
		this.switchListener = switchListener;
	}

	private void caculateRgb() {
		defRgbOffset = new int[] { offRgb[0] - onRgb[0], offRgb[1] - onRgb[1], offRgb[2] - onRgb[2] };
	}

	public void setOffRgb(int[] offRgb) {
		this.offRgb = offRgb;
		caculateRgb();
		invalidate();
	}

	public void setOnRgb(int[] onRgb) {
		this.onRgb = onRgb;
		caculateRgb();
		invalidate();
	}

}
